
#!/usr/bin/env python3
"""
eth_fcs.py  -- 以太网 II FCS 计算/校验工具
CRC-32 多项式：0x04C11DB7，初始值 0xFFFFFFFF，输入/输出都不反转，
最终结果按位取反，得到 4 字节 FCS。
用法见文件末尾示例。
"""

import struct

# CRC-32 表（直接模式，MSB-first）
POLY = 0x04C11DB7
_CRC_TABLE = []
for i in range(256):
    crc = i << 24
    for _ in range(8):
        crc = (crc << 1) ^ POLY if crc & 0x80000000 else crc << 1
        crc &= 0xFFFFFFFF
    _CRC_TABLE.append(crc)


def _crc32_update(crc: int, data: bytes) -> int:
    """逐字节更新 CRC-32 值"""
    for b in data:
        crc = ((crc << 8) & 0xFFFFFFFF) ^ _CRC_TABLE[(crc >> 24) ^ b]
    return crc


def calc_fcs(payload: bytes) -> bytes:
    """
    计算 payload（不含 FCS）的以太网 FCS
    :param payload: 从目的 MAC 到数据字段的完整字节串
    :return: 4 字节 FCS，可直接附加到帧尾
    """
    crc = _crc32_update(0xFFFFFFFF, payload)
    fcs = (~crc) & 0xFFFFFFFF
    return struct.pack(">I", fcs)


def verify_fcs(frame: bytes) -> bool:
    """
    校验完整帧（尾部 4 字节为 FCS）
    :param frame: 包含 FCS 的完整以太网帧
    :return: True 表示 FCS 正确
    """
    if len(frame) < 4:
        return False
    crc = _crc32_update(0xFFFFFFFF, frame)
    # 正确帧的 CRC 结果应为魔法值
    return crc == 0xC704DD7B


# ------------------------------------------------------------------
# 简单命令行演示
# ------------------------------------------------------------------
if __name__ == "__main__":
    # 构造一个最小合法帧：目的 MAC + 源 MAC + EtherType + 负载
    frame_without_fcs = (
        b"\xff\xff\xff\xff\xff\xff"      # 目的 MAC 广播
        b"\x48\x5f\x08\x4d\x20\x03"      # 源 MAC
        b"\x08\x06\x00\x01\x08\x00\x06\x04\x00\x01\x48\x5f\x08\x4d\x20\x03\xc0\xa8\x0a\x15"
        b"\x00\x00\x00\x00\x00\x00\xc0\xa8\x0a\x28\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"              # 假 IP 头开始
    )

# /fbe6851a
    fcs = calc_fcs(frame_without_fcs)
    full_frame = frame_without_fcs + fcs

    print("计算得到的 FCS:", fcs.hex())
    print("完整帧长度:", len(full_frame), "字节")

    # 验证
    ok = verify_fcs(full_frame)
    print("FCS 校验结果:", "PASS" if ok else "FAIL")